module ALU(A,B,Cin,Op,invA, invB,sign, Out, OFL, Zero);
	input [15:0] A,B;
	input Cin;
	input [2:0] Op;
	input invA;
	input invB;
	input sign;

	output [15:0] Out;
	output OFL;
	output Zero;

//choose whether or not to inverse A/B
	wire [15:0] AOp;
        wire [15:0] BOp;

	assign AOp = invA?(~A):A;
	assign BOp = invB?(~B):B;


//shifter
	wire [15:0] shift_out;
	shift_16 inst2(.In(AOp), .Cnt(BOp[3:0]), .Op(Op[1:0]), .Out(shift_out));

//adder
	wire [15:0] adder_out;
	wire adder_co;
	cla_adder_16 inst3(.A(AOp), .B(BOp), .CI(Cin), .SUM(adder_out), .CO(adder_co));

//arith part
	reg [15:0] arith_out;
	always @* case (Op[1:0])
	2'b00: arith_out = adder_out;
	2'b01: arith_out = AOp | BOp;
	2'b10: arith_out = AOp ^ BOp;
	2'b11: arith_out = AOp & BOp;
	endcase

//choose between shifrer or arith
	assign Out = Op[2]?arith_out:shift_out;

//set Zero
	assign Zero = (|Out)?0:1;

//for signed number, oveflow if sign bit disagree
	wire signed_ofl;
	assign signed_ofl = AOp[15]?(BOp[15]?(~Out[15]):0):(BOp[15]?0:Out[15]);

//choose signed overflow or unsigned overflow
	assign OFL = sign?signed_ofl:adder_co;

endmodule
